from typing import List
# 1. range(stop)：从 0 到 stop-1
for i in range(5):
    print(i)  # 输出：0, 1, 2, 3, 4
print("-------------------------")
# 2. range(start, stop)：从 start 到 stop-1
for i in range(2, 6):
    print(i)  # 输出：2, 3, 4, 5
print("-------------------------")
# 3. range(start, stop, step)：指定步长
for i in range(1, 10, 2):
    print(i)  # 输出：1, 3, 5, 7, 9（步长为 2，每次加 2）
print("-------------------------")
# 步长为负数时，生成递减序列
for i in range(5, 0, -1):
    print(i)  # 输出：5, 4, 3, 2, 1

print("-------------------------")

a = []
if(a):
    print("a对象是True")
else:
    print("a对象是False")
print('----------------')

a = [1,2,3,4,5]
print(a)

print(a[0:3])  ##不包括下标为3的数据


print(a[3:])  ##获取下标从3开始的所有数据(包括3)

print(a[:3]) ## 获取从第一个元素到索引为3（不包括3！）的元素

print(a[:-1])  ### 获取从第一个元素到最后一个元素的前一个元素之间的元素

print(a[:0])  ##[]

print(a[:-2])  # [1, 2, 3]  获取从第一个元素到最后一个元素的前二个元素之间的元素



map1 = {"height":180,"age":18}
print(map1) ##{'height': 180, 'age': 18}
print(map1["height"])  ##180

if(True):
    print("进入")


if(True):
    print("进入")

a = ""
print(len(a))
print("-------------------")

b = "a"
print(b[0:-1])
print(b[0:-1] == "")
print(b[0:-1] == None)


a = [1, 2, 3]  # 创建一个列表对象，变量a保存对该列表对象的引用
b = a  # 变量b也保存对同一个列表对象的引用
print("a,b的地址:",id(a), id(b))  # 使用id()函数查看对象的唯一标识，a和b的id相同  a,b的地址: 2313734576320 2313734576320


def modify_list(lst):
    lst.append(4)

my_list = [1, 2, 3]
modify_list(my_list)
print(my_list)  # 输出 [1, 2, 3, 4]  #这里 my_list 作为参数传递给 modify_list 函数，函数内部对 lst（即 my_list 的引用）指向的列表对象进行了修改，修改结果在函数外部可见。这类似于 Java 中传递引用类型参数



add  = lambda x, y: x + y
print(add(1, 2))

mul  = lambda x, y: x * y
print(mul(10, 2))

stus = [("lzq",100),("mlq",15),("gyy",20)]
#Python 内置的 sorted()
#lambda x: x[1] 是一个简化的匿名函数，x 代表列表中的每个元素（即每个元组，如 ("lzq",100)）；
print(sorted(stus, key=lambda x: x[1]))


stus2 = [("lzq", 100), ("mlq", 15), ("gyy", 20)]


#不想用匿名函数，那就如下这么显示的写出来就行
def get_score(tuple_item):
    return tuple_item[1]

# 用普通函数作为key参数  注意：key后面传的参数是方法(不带括号)，如果带了括号，传的就算是方法的返回值了
print(sorted(stus2, key=get_score))
print("--------------------")

def fibonacci(n):
    print("fibonacci方法被调用一次")
    a, b = 0, 1
    #在 Python 中，range(10) 会生成一个不可变的整数序列对象，表示从 0 开始、到 9 结束（不包含 10）的整数范围
    for _ in range(n):
        yield a
        '''
        在 Python 中，a, b = b, a + b 是同时赋值（也叫 “解包赋值”），其执行顺序是：
        先计算等号右边所有表达式的值，得到两个临时结果；
        再将这两个结果同时赋值给等号左边的变量。
        '''
        a, b = b, a + b

'''
fibonacci() 是一个生成器函数（包含 yield 关键字的函数），调用生成器函数时不会立即执行函数体内的代码，也不会返回计算结果，
而是返回一个生成器对象（generator object）。这个对象本质上是一个 “可迭代的迭代器”，它存储的是生成数据的 “逻辑”，而不是具体的数据。
为什么不是直接得到列表？
生成器的设计理念是 “惰性计算”，即需要数据时才会生成，而不是一次性生成所有数据并占用内存。这与直接返回列表的函数不同：
如果 fibonacci(10) 是普通函数，可能会返回 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]（直接生成所有数据）；
但作为生成器函数，它返回的是一个 “生成数据的工具”，需要通过迭代（如 for 循环、next() 函数）才能逐步获取数据。
'''
nums = fibonacci(10)

print("生成器对象地址:",nums) #<generator object fibonacci at 0x000001A8F7A66420>
print("生成器对象已创建，但print还没执行")
#注意,这里list(nums)的写法 就会把生成器 nums 里的所有元素都 “耗尽”
#print("###",list(nums))
print("for循环输出 即将开始")
for num in nums:
    '''
    list(nums)方法存在时，下面的循环输出 就不会输出了，原因如下；
    因为生成器是 “一次性迭代” 的，当你执行 list(nums) 时，已经把生成器 nums 里的所有元素都 “耗尽” 了，后续再用 for 循环迭代它，就没有元素可以遍历了
    '''
    print('#',num)


print("------------------元组-----------------")
# 用元组作为键，存储“城市+日期”对应的天气数据
weather_dict = {
    ("北京", "2024-10-01"): "晴",
    ("上海", "2024-10-01"): "多云"
}

# 访问数据 字典名[键名] 来获取值  python字典的规定写法
print(weather_dict[("北京", "2024-10-01")])  # 输出：晴

# 访问数据 字典名[键名] 来获取值  python字典的规定写法
dict2 = {"姓名":"刘再强","年龄":28}
print(dict2["姓名"])


print("元组的意义------------------------")
# 函数返回“两数的和与差”（本质返回元组 (sum, diff)）
def calculate(a, b):
    sum_ab = a + b
    diff_ab = a - b
    return sum_ab, diff_ab  # 等价于 return (sum_ab, diff_ab)

# 解包元组，直接获取两个返回值
total, difference = calculate(10, 3)
print(total)  # 输出：13
print(difference)  # 输出：7


# 存储“订单状态”常量（不允许修改）
ORDER_STATUS = ("待支付", "已支付", "已发货", "已完成")

# 业务逻辑中使用（只能读取，不能修改）
def check_status(status):
    if status not in ORDER_STATUS:
        print("无效的订单状态")
    else:
        print(f"订单状态：{status}")

check_status("已支付")  # 输出：订单状态：已支付
#ORDER_STATUS[0] = "待付款"  # 报错：无法修改元组元素


def process_config(config_list):
    # 将列表转为元组，防止内部误修改
    config_tuple = tuple(config_list)
    # 后续操作基于元组，无法修改原配置
    print(f"处理配置：{config_tuple}")

# 调用函数
original_config = [10, 20, 30]
process_config(original_config)
# original_config 不会被函数内部修改（因函数用的是元组）


#tuple1 = (10,20,30)

#print(tuple1)

list1 = [10,20,30]
tuple1 = tuple(list1)
print(tuple1) #(10, 20, 30)

#python用with语句自动管理资源
with open("a.txt","r") as file1:
    print(file1.readline())
    ##close调用 可以省略 with自动管理
    file1.close()

fruits  = ["苹果","香蕉"]
print("菠萝" in fruits)  #False
print("香蕉" in fruits) #True

a = [1,2,3]
b = a
c = [1,2,3]
print(a is b) #True
print(a is c) #False (虽然值相同，但是不是同一对象)


user = None
if(user is None):
    print("用户未定义")

a = 10
if(a>0 and a<30):
    print("ok")

print(2**3)  #8 2的3次方
print(9**0.5) #3.0  9开平方

print(9//2)  ## 4 向下取整
print(-9//2)## -5 向下取整


def divide(a,b):
    if b==0:
        raise ZeroDivisionError("除数不能为0!!!!")
    return a/b

print(divide(10,3))  ##3.3333333333333335   注意最后是5  精度已经开始损失
#print(divide(10,0))


class Animal:
    def eat(self):
        print("动物 吃东西")

#继承父类 直接在括号里写就行 java得用extends关键字
class Dog(Animal):
    def bark(self):
        print("狗 叫")

dog = Dog()
dog.bark() ##自身的方法
dog.eat() ##继承过来的方法


def main():
    print("程序主逻辑.........")
if __name__ == "__main__":
    main()

list1 = [1,2]
list1+=[3,4]
print(list1)  #[1, 2, 3, 4]

s = "hello "
s+="world"
print(s) # hello world

#python可以一次为多个变量赋值
a,b,c= 1,2,3
#python的链式赋值
x=y=z = 0
print(a,b,c,x,y,z)

#python用列表代替数组，且元素类型可以混合
mixed_list   = ["hello",1,True,(1,2,3,4)]
print(mixed_list) #['hello', 1, True, (1, 2, 3, 4)]


def sum(a,b,c):
    return a+b+c

list1 = [1,2,3]
#* 用于解包序列（如列表、元组） 把序列中的元素逐个 “解包”，按顺序传递给函数的位置参数（即不指定参数名，只按顺序匹配）。
print(sum(*list1)) #等价于sum(1,2,3)

dict1 = {"a":1,"b":2,"c":3}
# ** 用于解包字典 作用：把字典中的键值对逐个 “解包”，传递给函数的关键字参数（即 参数名=值 的形式）。
#这里对字典进行解包，如果只用一个*,会报错： 原因是：*params 会将字典的键 ["a", "b", "c"] 作为位置参数传递给 sum 函数，等价于 sum("a", "b", "c")。而函数 sum 试图对字符串做加法，显然不符合预期。
#因此，对字典进行解包时，若要传递键值对，必须使用 **  使用 * 只会传递键，通常不符合函数对参数的要求（除非函数参数本身需要字符串类型的键）。
print(sum(**dict1))  ##等价于sum(a=1,b2=2,c=3)

print("----------操作全局变量--------------")
count = 0
print(count)
def incre():
    global count
    count += 1  #如果不加global count 会报错，UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
    return count
print(incre())

print(count)
print(count)

list = []
if not list:
    print("这是一个空列表")


#python支持集合推导式
seq = {x**2 for x in range(10)}
#集合（set）是无序、不重复的元素集合，上述代码生成的结果 {0, 1, 64, 4, 36, 9, 16, 49, 81, 25} 正是符合集合特性的数值集合（元素无重复，且打印顺序可能不固定）。
print(type(seq),seq)  #<class 'set'> {0, 1, 64, 4, 36, 9, 16, 49, 81, 25}}

dic = {x:x**2+2 for x in range(5)}
print(dic)  #{0: 2, 1: 3, 2: 6, 3: 11, 4: 18}


class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def bark(self):
        print(f"{self.age}岁的{self.name} says Woof!")

my_dog = Dog("Buddy", 3)
my_dog.bark()

i= 1
f1 = 1.2345
f2=1.23e4
print(f1*f2)  #15184.349999999999  精度又开始损失了 准确值应该为：15184.35

#复数（complex）：由实部和虚部组成，形式为 a + bj，其中 a 是实部，b 是虚部 ，比如 3 + 4j 。
complex1 = 2+3j
print(complex1) #(2+3j)


#三引号常用来表示需要换行的字符串
s = '''
白日依山尽
黄河入海流
'''
#白日依山尽
#黄河入海流
print(s)


s = ("白日依山尽"+
    "黄河入海流")
print(s)  #白日依山尽黄河入海流


#元组（tuple）：也是有序的数据集合，但与列表不同，元组是不可变的，用小括号 () 表示。例如 (1, 2, 3) ，常用于存储一组不希望被修改的数据。
tuple = (1,"Hello",True)
print(tuple)
print(tuple[2]) #可以通过下标获取到元组指定位置的值


dic1 = {"name":"xju","age":101}
print(dic1)
print(dic1["name"])  #xju 字典根据键名取值 必须用中括号




set1 = {1,1,2,3}
set2 = {2,3,4,5}
#set1 = {}
print(type(set1),set1)  #<class 'set'> {1, 2, 3}
print(set1.difference(set2)) #{1}  可以理解为set1有，set2没有的
print(set2.difference(set1)) #{4, 5} 可以理解为set2有，set1没有的

print(set1.intersection(set2)) #{2, 3}  理解为交集

set3 = {1,2,3}
set3.add(4)
print(set3) #{1, 2, 3, 4}


#冻结集合（frozenset）：与集合类似，也是无序不重复元素的集合，但它是不可变的，一旦创建就不能再添加或删除元素，使用 frozenset() 函数创建，例如 frozenset([1, 2, 3]) 。
set4 = frozenset([1, 2, 3])
print(set4)  #frozenset({1, 2, 3})'
print(set4.intersection(set4)) #frozenset({1, 2, 3})

def test():
    pass

print(test())  #None

#print(hello) 报错： #NameError: name 'hello' is not defined

def operation(a, b, op):
    ops = {
        '+': a + b,      # 键 '+' 对应“执行加法”
        '-': a - b,      # 键 '-' 对应“执行减法”
        '*': a * b,      # 键 '*' 对应“执行乘法”
        '/': a / b       # 键 '/' 对应“执行除法”
    }
    return ops.get(op, "无效操作")  # 根据op取对应值，没有则返回“无效操作”


print(operation(2, 3, '+'))  # 输出：5（执行2+3）
print(operation(5, 2, '-'))  # 输出：3（执行5-2）
print(operation(4, 2, '/'))  # 输出：2.0（执行4/2）
print(operation(2, 3, '^'))  # 输出：无效操作（op='^' 不在字典的键中）

def handle_command(command):
    match command:
        case "start":
            print("启动程序...")
        case "stop":
            print("停止程序...")
        case "restart":
            print("重启程序...")
        case "status":
            print("程序运行中")
        case _:  # 相当于 default
            print(f"未知命令: {command}")

# 测试不同的命令
handle_command("start")    # 输出: 启动程序...
handle_command("status")   # 输出: 程序运行中
handle_command("pause")    # 输出: 未知命令: pause

print("--------------------------")
'''
atch-case 的 “类型模式 + 守卫条件” 是顺序且分层的：
只有先满足 “类型 / 结构匹配”，才会执行后面的 if 条件；
如果类型不匹配，直接跳过该 case，不会触发 “类型不兼容的条件判断”，因此不会报错。
所以字符串永远不会进入 case int(n) if n > 10 的条件判断，自然不会因 n > 10 报错～ 
'''
#python的case 分支默认是互斥的，一旦匹配成功就会退出整个 match 结构。 所以 基本不需要加break
def process_data(data):
    match data:
        case 0:
            print("数据为零")
        case 1 | 2 | 3:
            print("数据为 1-3 之间的整数")
        case int(n) if n > 10:
            print(f"大于 10 的整数: {n}")
        case str(s) if len(s) > 5:
            print(f"长度大于 5 的字符串: {s}")
        case [x, y, z]:
            print(f"包含三个元素的列表: {x}, {y}, {z}")
        case _:
            print(f"未匹配的数据: {data}")


process_data(0)                  # 数据为零
process_data(2)                  # 数据为 1-3 之间的整数
process_data(15)                 # 大于 10 的整数: 15
process_data("hello world")      # 长度大于 5 的字符串: hello world
process_data([10, 20, 30])       # 包含三个元素的列表: 10, 20, 30
process_data({"name": "Alice"})  # 未匹配的数据: {'name': 'Alice'}


print("----------------------异常链................")



try:
    1 / 1   #如果除数是0的话 触发 ZeroDivisionError（除以零错误）
except ZeroDivisionError as e:
    # 捕获 ZeroDivisionError 后，抛出新的 ValueError，并关联原始异常 e
    raise ValueError("计算错误") from e

print("--------------------------------")
dic1 = {"name":"lzq","age":28}
for k in dic1:
    print(k)
#name
#age
#for k in dic1 遍历的是字典的键


name = 'lzq'
age = 28
print("{}岁的{}".format(age,name))  #28岁的lzq

print(f"{age}岁的{name}") #28岁的lzq

print("%d岁的%s" % (age,name)) #28岁的lzq


big_num1 = 12345678999999999999991234567899999999999999123456789999999999999912345678999999999999991234567899999999999999123456789999999999999912345678999999999999991234567899999999999999123456789999999999999912345678999999999999991234567899999999999999123456789999999999999912345678999999999999991234567899999999999999
big_num2 = 1234567899999999999999123456789999999999999912345678999999999999991234567899999999999999123456789999999999999912345678999999999999991234567899999999999999123456789999999999999912345678999999999999991234567899999999999999123456789999999999999912345678999999999999991234567899999999999999
print(type(big_num1),type(big_num2)) # <class 'int'> <class 'int'>

print("-----------------------------")
list = [("lzq",20),("yaoyao",12),("ok",22),("shijun",23),("yaning",8)]
#list = sorted(list,key=lambda x:x[1],reverse=True)
list = sorted(list,key=lambda one:one[1] ,reverse=True)
print(list) #[('shijun', 23), ('ok', 22), ('lzq', 20), ('yaoyao', 12), ('yaning', 8)]


print("---------------")
from typing import Callable
def apply_func(func: Callable[[int, int], int], a: int, b: int) -> int:
    return func(a, b)  # func 是一个接收两个 int、返回 int 的函数
# 测试：传入加法函数
print(apply_func(lambda x, y: x + y, 2, 3))  # 输出 5


def func(*args):
    print(type(args))  # 输出：<class 'tuple'>
    print(args)  # 输出传入的参数打包成的元组 (1, 2, 3)


func(1, 2, 3)  # 调用时传入3个位置参数


def func(a, b, c):
    print(a, b, c)


params = (1, 2, 3)
func(*params)  # 等价于 func(1, 2, 3)，* 将元组解包成3个参数 这里的 *params 就是 “解包” 操作，和定义时的 *args（打包）是相反的过程。
# 输出：1 2 3


# 以下是设置的特殊标签 不用管
#      TODO 待办
# FIXME:这里可能有除0错误，需要进一步判断
# FIXME: 这里可能有除0错误，需要进一步判断
# XXX 这个循环效率太低，数据量大时会卡顿，建议改用列表推导式
# NOTE: 此处使用了缓存机制，避免重复计算，有效期10分钟
# BUG: 当输入为负数时，返回值始终为0，需修复
# HACK 标记 “取巧的临时解决方案”（可能不符合规范，但暂时能工作），提醒后续重构。